#pragma once

#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>
#include <jsoncpp/json/json.h>
#include <vector>
#include <map>
#include "../poco/learn-status.hh"
#include "../util/config.hh"
#include "../util/dbconn.hh"
#include "../util/util.hh"

namespace WordMemory
{
    class LearnRepository
    {
    public:
        static LearnRepository& instance()
        {
            static LearnRepository inst;
            return inst;
        }

    public:
        Json::Value getLearningStats(int user_id)
        {
            ConnectionGuard conn;
            try
            {
                Json::Value stats;

                // 统计总单词数
                std::unique_ptr<sql::PreparedStatement> total_stmt(
                    conn.get()->prepareStatement(
                        "SELECT COUNT(DISTINCT word_id) AS total_words "
                        "FROM word_status "
                        "WHERE user_id = ?"));
                total_stmt->setInt(1, user_id);
                std::unique_ptr<sql::ResultSet> total_res(total_stmt->executeQuery());
                stats["total_words"] = total_res->next() ? total_res->getInt("total_words") : 0;

                // 统计各状态数量
                std::unique_ptr<sql::PreparedStatement> status_stmt(
                    conn.get()->prepareStatement(
                        "SELECT status, COUNT(*) AS count "
                        "FROM word_status "
                        "WHERE user_id = ? "
                        "GROUP BY status"));
                status_stmt->setInt(1, user_id);
                std::unique_ptr<sql::ResultSet> status_res(status_stmt->executeQuery());

                stats["learned"] = 0; // Renamed from "known" for client consistency
                stats["forgot"] = 0;
                stats["vague"] = 0;
                while (status_res->next())
                {
                    std::string status_val = status_res->getString("status"); // Renamed to avoid conflict
                    int count = status_res->getInt("count");
                    if (status_val == "known")
                        stats["learned"] = count; // Client expects "learned"
                    else if (status_val == "forgot")
                        stats["forgot"] = count;
                    else if (status_val == "vague")
                        stats["vague"] = count;
                }

                return stats;
            }
            catch (const sql::SQLException& e)
            {
                spdlog::error("LearnRepository: Failed to get learning stats for user_id {}: {}", user_id, e.what());
                throw RepositoryExcept("Failed to get learning stats: " + std::string(e.what()));
            }
        }

        // 获取近30天每日学习统计
        std::vector<DailyLearningStat> getDailyLearningSummary(int user_id, int days = 30)
        {
            ConnectionGuard conn;
            std::vector<DailyLearningStat> daily_summary;
            std::map<std::string, DailyLearningStat> summary_map;
            auto now = std::chrono::system_clock::now();

            for (int i = 0; i < days; ++i) {
                auto date_tp = now - std::chrono::hours(24 * i);
                std::time_t date_time_t = std::chrono::system_clock::to_time_t(date_tp);
                std::tm date_tm = *std::localtime(&date_time_t); // Use localtime for local date
                char buffer[11];
                std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &date_tm);
                std::string date_str(buffer);

                summary_map[date_str].date = date_str; // Initialize with 0 counts
            }


            try
            {
                std::string query_str =
                    "SELECT DATE(updated_at) as review_date, status, COUNT(*) as count "
                    "FROM word_status "
                    "WHERE user_id = ? AND updated_at >= CURDATE() - INTERVAL ? DAY "
                    "GROUP BY DATE(updated_at), status "
                    "ORDER BY review_date DESC, status ASC";

                std::unique_ptr<sql::PreparedStatement> pstmt(conn.get()->prepareStatement(query_str));
                pstmt->setInt(1, user_id);
                pstmt->setInt(2, days - 1); // Interval is inclusive of start day, so days-1 for 'last N days'
                std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

                while (res->next())
                {
                    std::string date = res->getString("review_date");
                    std::string status = res->getString("status");
                    int count = res->getInt("count");

                    if (summary_map.find(date) == summary_map.end()) {
                        continue;
                    }

                    DailyLearningStat& day_stat = summary_map[date];

                    if (status == "forgot") day_stat.forgot_count = count;
                    else if (status == "vague") day_stat.vague_count = count;
                    else if (status == "known") day_stat.known_count = count;
                }

                for (auto const& [date_key, stat_val] : summary_map) {
                    daily_summary.push_back(stat_val);
                }

                std::sort(daily_summary.begin(), daily_summary.end(), [](const DailyLearningStat& a, const DailyLearningStat& b) {
                        return a.date < b.date;
                    });


                return daily_summary;
            }
            catch (const sql::SQLException& e)
            {
                spdlog::error("LearnRepository: Failed to get daily learning summary for user_id {}: {}", user_id, e.what());
                throw RepositoryExcept("Failed to get daily learning summary: " + std::string(e.what()));
            }
        }

    private:
        LearnRepository() = default;
        LearnRepository(const LearnRepository&) = delete;
        LearnRepository& operator=(const LearnRepository&) = delete;
    };
}